﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using FrontDisplay.Controls;

namespace FrontDisplay
{
    public static class ThemeManager
    {
        public static readonly string ThemesDir = Utility.MapPath("Colors");

        public static SolidColorBrush TextBrush { get; private set; }
        public static SolidColorBrush TextShadow { get; private set; }

        public static SolidColorBrush Background { get; private set; }
        public static SolidColorBrush BackgroundTop { get; private set; }
        public static SolidColorBrush BackgroundBottom { get; private set; }

        private static List<ColorTheme> _colorThemes = new List<ColorTheme>();

        private static List<IBackground> _backgrounds = new List<IBackground>();

        private static ColorTheme _current;

        public static ColorTheme Current
        {
            get
            {
                return _current;
            }
        }

        private static IBackground _currentBackground;

        public static IBackground CurrentBackground
        {
            get
            {
                return _currentBackground;
            }
            private set
            {
                if ((_currentBackground != null) && (_currentBackground is IAnimatedBackground))
                {
                    ((IAnimatedBackground) _currentBackground).Stop();
                }
                
                _currentBackground = value;

                if ((_currentBackground != null) && (_currentBackground is IAnimatedBackground))
                {
                    ((IAnimatedBackground)_currentBackground).Start();
                }
            }
        }

        public static IEnumerable<ColorTheme> ColorThemes
        {
            get
            {
                return _colorThemes;
            }
        }

        public static IEnumerable<IBackground> Backgrounds
        {
            get
            {
                return _backgrounds;
            }
        }

        static ThemeManager()
        {
            //TODO:
            _current = new ColorTheme();

            if (Directory.Exists(ThemesDir))
            {
                foreach (string fileName in Directory.GetFiles(ThemesDir))
                {
                    ColorTheme colorTheme = ColorTheme.ReadFromFile(Path.GetFileNameWithoutExtension(fileName));
                    _colorThemes.Add(colorTheme);
                    if (Global.Config.Theme == colorTheme.Name)
                    {
                        _current = colorTheme;
                    }
                }
            }

            TextBrush = new SolidColorBrush(_current.TextForeground);
            TextShadow = new SolidColorBrush(_current.TextShadow);
            BackgroundTop = new SolidColorBrush(_current.BackgroundTop);
            Background = new SolidColorBrush(_current.Background);
            BackgroundBottom = new SolidColorBrush(_current.BackgroundBottom);

            //TODO:
            _currentBackground = new Gradient();

            //TODO: Initialization
            Assembly assembly = Assembly.GetExecutingAssembly();
            IEnumerable<Type> pluginsTypes = assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && typeof(IBackground).IsAssignableFrom(t));

            foreach (Type backgroundType in pluginsTypes)
            {
                if (backgroundType == typeof(InfoPage)) continue;
                IBackground background = (IBackground) Activator.CreateInstance(backgroundType);
                _backgrounds.Add(background);
                if (Global.Config.Background == background.Name)
                {
                    CurrentBackground = background;
                }
            }
        }

        /// <summary>
        /// Update theme's colors according to configuration values.
        /// This update is without animation.
        /// </summary>
        public static void UpdateThemeColors()
        {
            TextBrush.Color = _current.TextForeground;
            TextShadow.Color = _current.TextShadow;
            BackgroundTop.Color = _current.BackgroundTop;
            Background.Color = _current.Background;
            BackgroundBottom.Color = _current.BackgroundBottom;
            CurrentBackground.UpdateColors();
        }

        //TODO:
        public static void UpdateBackground()
        {
            //TODO:
            foreach (var item in _backgrounds)
            {
                if (item.Name == Global.Config.Background)
                {
                    CurrentBackground = item;
                    break;
                }
            }
            if ((Global.MainPanel != null) && (Global.MainPanel.Children.Count > 0))
            {
                UpdateControlBackground(Global.MainPanel.Children[0]);
            }
        }

        public static void UpdateColors()
        {
            //TODO:
            ColorTheme theme = GetThemeByName(Global.Config.Theme);

            if (theme == null)
            {
                theme = ColorTheme.ReadFromFile(Global.Config.Theme);
                _colorThemes.Add(theme);
            }
            if (theme != null)
            {
                _current = theme;
            }

            AnimateColors();
        }

        private static void AnimateColors()
        {
            Duration duration = new Duration(TimeSpan.FromMilliseconds(1000));
            ColorAnimationEx colorAnimation = new ColorAnimationEx(Current.Background, duration);
            colorAnimation.ColorChanged += ColorsChanged;

            TextBrush.BeginAnimation(SolidColorBrush.ColorProperty, new ColorAnimation(Current.TextForeground, duration));
            TextShadow.BeginAnimation(SolidColorBrush.ColorProperty, new ColorAnimation(Current.TextShadow, duration));
            BackgroundTop.BeginAnimation(SolidColorBrush.ColorProperty, new ColorAnimation(Current.BackgroundTop, duration));
            Background.BeginAnimation(SolidColorBrush.ColorProperty, colorAnimation);
            BackgroundBottom.BeginAnimation(SolidColorBrush.ColorProperty, new ColorAnimation(Current.BackgroundBottom, duration));
        }

        //TODO: investigate this method
        static void AllowUIToUpdate()
        {
            DispatcherFrame frame = new DispatcherFrame();

            Dispatcher.CurrentDispatcher.BeginInvoke(
                DispatcherPriority.Render, 
                new DispatcherOperationCallback(delegate
                {
                    frame.Continue = false;
                    return null;
                }),
                null);
            Dispatcher.PushFrame(frame);
        }

        static void ColorsChanged(object sender, EventArgs e)
        {
            _currentBackground.UpdateColors();

            MainWindow.ThemeChanged();

            AllowUIToUpdate();
        }

        public static void SelectNext()
        {
            if (_colorThemes.Count == 0) return;

            int num = _colorThemes.IndexOf(_current);
            num++;

            if (num >= _colorThemes.Count)
            {
                num = 0;
            }

            _current = _colorThemes[num];
            Global.Config.Theme = _current.Name;
        }

        public static void UpdateControlForeground(UIElement control)
        {
            if (control == null) return;

            control.SetValue(Control.ForegroundProperty, TextBrush);
            
            if ((control is OutlineTextBlock))
            {
                control.SetValue(OutlineTextBlock.StrokeProperty, TextShadow);
                return;
            }
            //if ((control is Path) || (control is Ellipse))
            //{
            //    control.SetValue(Shape.StrokeProperty, TextBrush);
            //}

            if (control is ContentControl)
            {
                UIElement content = ((ContentControl)control).Content as UIElement;
                if (content != null)
                {
                    UpdateControlForeground(content);
                }
                return;
            }

            if (control is ItemsControl)
            {
                foreach (object item in ((ItemsControl)control).Items)
                {
                    UpdateControlForeground(item as UIElement);
                }
                return;
            }

            if (control is Panel)
            {
                foreach (object item in ((Panel)control).Children)
                {
                    UpdateControlForeground(item as UIElement);
                }
                return;
            }

            if (control is Decorator)
            {
                UpdateControlForeground(((Decorator)control).Child);
                return;
            }
        }

        public static void UpdateControlBackground(UIElement control)
        {
            if (control == null) return;

            control.SetValue(Control.BackgroundProperty, CurrentBackground.Brush);
        }

        public static ColorTheme GetThemeByName(string themeName)
        {
            foreach (var item in _colorThemes)
            {
                if (item.Name == themeName)
                {
                    return item;
                }
            }
            return null;
        }
    }
}
